package com.gwm.order.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.wxpay.sdk.WXPayUtil;
import com.gwm.common.enums.ExceptionEnums;
import com.gwm.common.exceptions.LyException;
import com.gwm.common.threadlocals.UserHolder;
import com.gwm.common.utils.BeanHelper;
import com.gwm.common.utils.IdWorker;
import com.gwm.item.client.ItemClient;
import com.gwm.item.dto.SkuDTO;
import com.gwm.order.config.PayProperties;
import com.gwm.order.dto.CartDTO;
import com.gwm.order.dto.OrderDTO;
import com.gwm.order.entity.TbOrder;
import com.gwm.order.entity.TbOrderDetail;
import com.gwm.order.entity.TbOrderLogistics;
import com.gwm.order.entity.TbOrderSeckillDetail;
import com.gwm.order.enums.BusinessTypeEnum;
import com.gwm.order.enums.OrderStatusEnum;
import com.gwm.order.vo.OrderDetailVO;
import com.gwm.order.vo.OrderLogisticsVO;
import com.gwm.order.vo.OrderVO;
import com.gwm.seckill.client.SeckillClient;
import com.gwm.seckill.pojo.OrderSecKillDTO;
import com.gwm.seckill.pojo.SeckillPolicyDTO;
import com.gwm.user.client.UserClient;
import com.gwm.user.dto.UserAddressDTO;
import com.sun.xml.internal.bind.v2.TODO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.gwm.order.enums.BusinessTypeEnum.SEC_KILL;
import static com.gwm.order.enums.OrderStatusEnum.INIT;

@Service
@Slf4j
public class OrderService {

    @Autowired
    private TbOrderService orderService;
    @Autowired
    private TbOrderDetailService orderDetailService;
    @Autowired
    private TbOrderLogisticsService orderLogisticsService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private ItemClient itemClient;
    @Autowired
    private UserClient userClient;
    @Autowired
    private PayProperties payProperties;
    @Autowired
    private RestTemplate restTemplate;
    private static String PAY_URL="PAY:ORDER:URL:";//前缀
    @Autowired
    private TbOrderSeckillDetailService orderSeckillDetailService;
    @Autowired
    private SeckillClient seckillClient;

    @Transactional
    public  Long createOrder(OrderDTO orderDTO) {
        String userId = UserHolder.getUserId();

        TbOrder tbOrder = new TbOrder();
        tbOrder.setUserId(Long.parseLong(userId));
        long orderId = idWorker.nextId(); //通过分布式id生成算法（推特开源的雪花算法）获取订单号
        tbOrder.setOrderId(orderId);
        tbOrder.setPaymentType(orderDTO.getPaymentType()); //记得把这个属性的类型改成Integer
        tbOrder.setStatus(INIT.value());
        tbOrder.setBType(BusinessTypeEnum.MALL.value());
        tbOrder.setPostFee(0L);

//        总金额通过计算
        List<CartDTO> carts = orderDTO.getCarts();
      /*  2868435   1
        2868433   3*/
        Map<Long, Integer> skuIdAndNumMap = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));

        List<Long> skuIdList = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());
//        查询这批订单下的sku数据 price
//        List<SkuDTO> skuList = itemClient.findSkuListBySkuIds(skuIdList);
        List<SkuDTO> skuList = itemClient.findSkuListBySkuIds(skuIdList);
//        通过skuId集合获取Sku对象集合
        Long totalFee = 0L;
        List<TbOrderDetail> orderDetailList = new ArrayList<>();
        for (SkuDTO sku : skuList) {
           Integer num = skuIdAndNumMap.get(sku.getId());
           totalFee+= sku.getPrice()*num;

            TbOrderDetail tbOrderDetail = BeanHelper.copyProperties(sku, TbOrderDetail.class);
            tbOrderDetail.setSkuId(sku.getId());
            tbOrderDetail.setNum(num);
            tbOrderDetail.setOrderId(orderId);
            tbOrderDetail.setImage(StringUtils.substringBefore(sku.getImages(),","));// 121,334r,efwe
            orderDetailList.add(tbOrderDetail);

       }

        tbOrder.setTotalFee(totalFee);
        tbOrder.setActualFee(totalFee); //实付金额


        UserAddressDTO userAddress = userClient.findById(Long.valueOf(userId), orderDTO.getAddressId());
        TbOrderLogistics orderLogistics = BeanHelper.copyProperties(userAddress, TbOrderLogistics.class);
        orderLogistics.setOrderId(orderId);





        boolean save = orderService.save(tbOrder);
        if(!save){
            throw new LyException(ExceptionEnums.INSERT_OPERATION_FAIL);
        }
        save = orderDetailService.saveBatch(orderDetailList);
        if(!save){
            throw new LyException(ExceptionEnums.INSERT_OPERATION_FAIL);
        }
        save = orderLogisticsService.save(orderLogistics);
        if(!save){
            throw new LyException(ExceptionEnums.INSERT_OPERATION_FAIL);
        }

        //        减库存 操作sku表中的stock字段
        itemClient.stockMinus(skuIdAndNumMap);

        return orderId;
    }

    public OrderVO findOrderVoById(Long orderId) {
//        TbOrder tbOrder = orderService.getById(orderId); //这里最好不要拿着id直接获取
//        1、订单id  2、用户id 3、状态（未付款）
        String userId = UserHolder.getUserId();
        QueryWrapper<TbOrder> tbOrderQueryWrapper = new QueryWrapper<>();
        tbOrderQueryWrapper.lambda().eq(TbOrder::getOrderId,orderId);
        tbOrderQueryWrapper.lambda().eq(TbOrder::getUserId,Long.parseLong(userId));
        tbOrderQueryWrapper.lambda().eq(TbOrder::getStatus, INIT.value());
        TbOrder tbOrder = orderService.getOne(tbOrderQueryWrapper);
        if(tbOrder==null){
            throw new LyException(ExceptionEnums.ORDER_NOT_FOUND);
        }
        OrderVO orderVO = BeanHelper.copyProperties(tbOrder, OrderVO.class);
        TbOrderLogistics orderLogistics = orderLogisticsService.getById(orderId);
        OrderLogisticsVO orderLogisticsVO = BeanHelper.copyProperties(orderLogistics, OrderLogisticsVO.class);
        orderVO.setLogistics(orderLogisticsVO);
        QueryWrapper<TbOrderDetail> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(TbOrderDetail::getOrderId,orderId);
        List<TbOrderDetail> tbOrderDetailList = orderDetailService.list(queryWrapper);
        List<OrderDetailVO> orderDetailVOS = BeanHelper.copyWithCollection(tbOrderDetailList, OrderDetailVO.class);
        orderVO.setDetailList(orderDetailVOS);
        return orderVO;

    }


    public void cleanOverTimeOrder() {
        log.debug("执行了清理订单的方法");
     /*
        2、 修改需要清理的订单 的状态  update tb_order set status = 5 where  status=1 and    TIMESTAMPDIFF(MINUTE, create_time,NOW()) >60

        3、恢复库存 商品微服务
        */
//        查询这些需要清理的订单有哪些商品和数量
        List<TbOrderDetail> orderDetailList = orderDetailService.findOverTimeOrderDetail();
        if(CollectionUtils.isEmpty(orderDetailList)){
            return;//表示没有超时的订单
        }

//        修改需要清理的订单 的状态
        orderService.updateOverTimeOrderStatus();

        Map<Long, Integer> skuIdAndNumMap = orderDetailList.stream().collect(Collectors.toMap(TbOrderDetail::getSkuId, TbOrderDetail::getNum));
        itemClient.stockPlus(skuIdAndNumMap);

    }

    public OrderVO findOrderById(Long orderId) {

        // 判断用户id是否正确
        String userId = UserHolder.getUserId();
//        订单状态,初始状态
        Integer status = INIT.value();
        // 1.查询订单  只能是当前登录人查询未支付的订单
        TbOrder tbOrder = orderService.findOrder(orderId,userId,status);
        if (tbOrder == null) {
            // 不存在
            throw new LyException(ExceptionEnums.ORDER_NOT_FOUND);
        }
        if (!userId.equals(tbOrder.getUserId().toString())) {
            throw new LyException(ExceptionEnums.ORDER_NOT_FOUND);
        }
        orderId = tbOrder.getOrderId();

        // 2. 查询订单详情
        QueryWrapper<TbOrderDetail> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(TbOrderDetail::getOrderId,orderId);
        List<TbOrderDetail> tbOrderDetailList = orderDetailService.list(queryWrapper);
        if(CollectionUtils.isEmpty(tbOrderDetailList)){
            throw new LyException(ExceptionEnums.ORDER_NOT_FOUND);
        }

        // 3.查询订单状态
        TbOrderLogistics tbOrderLogistics = orderLogisticsService.getById(orderId);
        if (tbOrderLogistics == null) {
            // 不存在
            throw new LyException(ExceptionEnums.ORDER_NOT_FOUND);
        }

        // 4.封装数据
        OrderVO orderVO = BeanHelper.copyProperties(tbOrder, OrderVO.class);
        orderVO.setDetailList(BeanHelper.copyWithCollection(tbOrderDetailList, OrderDetailVO.class));
        orderVO.setLogistics(BeanHelper.copyProperties(tbOrderLogistics, OrderLogisticsVO.class));
        return orderVO;
    }



    /**
     * 创建秒杀订单
     *
     * @param orderSecKillDTO
     * @return
     */
    @Transactional
    public Long createSecKillOrder(OrderSecKillDTO orderSecKillDTO) {
        //        订单中秒杀id
        Long seckillId = orderSecKillDTO.getSeckillId();
        //        获取秒杀信息
        SeckillPolicyDTO seckillPolicyDTO = seckillClient.findSecKillPolicyById(seckillId);
        //订单表
        TbOrder tbOrder = new TbOrder();
        //        设置业务类型，当前为秒杀
        tbOrder.setBType(SEC_KILL.value());
        //订单编号,从seckill微服务中传过来的
        Long orderId = orderSecKillDTO.getOrderId();
        tbOrder.setOrderId(orderId);
        //获取秒杀订单金额
        Long costPrice = seckillPolicyDTO.getCostPrice();
        //        订单总金额
        tbOrder.setTotalFee(costPrice);
        //TODO 目前全场包邮
        tbOrder.setPostFee(0L);
        //TODO 实付金额 要减去优惠金额，通过优惠id获取金额
        tbOrder.setActualFee(costPrice + tbOrder.getPostFee());
        //        支付类型
        tbOrder.setPaymentType(orderSecKillDTO.getPaymentType());
        //        设置用户id
        Long userId = orderSecKillDTO.getUserId();
        tbOrder.setUserId(userId);
        //        订单状态 初始状态
        tbOrder.setStatus(INIT.value());
        // 写order到数据库
        boolean b = orderService.save(tbOrder);
        if (!b) {
            log.error("【新增秒杀订单】保存order表错误");
            throw new LyException(ExceptionEnums.INSERT_OPERATION_FAIL);
        }
        // 2 写OrderDetail
        // 创建TbOrderSeckillDetail
        TbOrderSeckillDetail tbOrderSeckillDetail = BeanHelper.copyProperties(seckillPolicyDTO, TbOrderSeckillDetail.class);
        tbOrderSeckillDetail.setNum(1);
        tbOrderSeckillDetail.setSeckillId(seckillId);
        tbOrderSeckillDetail.setOrderId(orderId);
        boolean bDetail = orderSeckillDetailService.save(tbOrderSeckillDetail);
        if (!bDetail) {
            log.error("【新增秒杀订单】保存orderSeckillDetail表错误");
            throw new LyException(ExceptionEnums.INSERT_OPERATION_FAIL);
        }
        // 3 写orderLogistics
        Long addressId = orderSecKillDTO.getAddressId();
        // 3.1.查询收货地址
        UserAddressDTO addressDTO = userClient.findById(addressId,userId);
        log.info("addressDTO {}",addressDTO);
        // 3.2.填写物流信息
        TbOrderLogistics tbOrderLogistics = BeanHelper.copyProperties(addressDTO, TbOrderLogistics.class);
        tbOrderLogistics.setOrderId(orderId);
        boolean bLogistic = orderLogisticsService.save(tbOrderLogistics);
        if (!bLogistic) {
            log.error("【新增订单】保存orderLogistics物流信息表错误");
            throw new LyException(ExceptionEnums.INSERT_OPERATION_FAIL);
        }
        // 4 减库存
        seckillClient.minusStock(seckillId);
        return orderId;
    }


    public OrderVO findOrderByOrderId(Long orderId) {
       return orderService.findOrderByOrderId(orderId);
    }

//todo
//    public String createPayUrl(Long orderId) {
//
//        // 判断用户id是否正确
//        String userId = UserHolder.getUserId();
//        if(StringUtils.isEmpty(userId)){
//            throw new LyException(ExceptionEnums.UNAUTHORIZED);
//        }
//        //        从redis中获取
//        String code_url = redisTemplate.boundValueOps(PAY_URL + orderId).get();
//        if(StringUtils.isNotBlank(code_url)){
//            return code_url;
//        }
//        try {
//            Order order = orderMapper.selectByPrimaryKey(orderId);
//            // 1、组装微信统一下单API所需要的必填参数
//            Map<String,String> paramMap = new HashMap<>();
//            paramMap.put("appid",payProperties.getAppID());
//            paramMap.put("mch_id",payProperties.getMchID());
//            paramMap.put("nonce_str", WXPayUtil.generateNonceStr());//随机数
//            paramMap.put("body","乐优商城");
//            paramMap.put("out_trade_no",orderId.toString());
//            //            paramMap.put("total_fee",order.getActualFee().toString()); //实际支付的价格 单位是分
//            paramMap.put("total_fee","1"); // 测试时 使用1分钱
//            paramMap.put("spbill_create_ip","127.0.0.1");
//            paramMap.put("notify_url",payProperties.getNotifyurl());//  回调地址
//            paramMap.put("trade_type","NATIVE");
//            //将参数转xml
//            String paramXml = WXPayUtil.generateSignedXml(paramMap, payProperties.getKey());
//            //2、基于httpclient工具类，调用微信支付平台，完成支付操作
//            String resultString = restTemplate.postForObject("https://api.mch.weixin.qq.com/pay/unifiedorder", paramXml, String.class);
//            Map<String, String> stringStringMap = WXPayUtil.xmlToMap(resultString);
//            code_url = stringStringMap.get("code_url");
//            //            放入到redis中  限时两个小时
//            redisTemplate.boundValueOps(PAY_URL + orderId).set(code_url,2, TimeUnit.HOURS);
//            return code_url;
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new LyException(ExceptionEnum.INVALID_ORDER_STATUS);
//        }
//
//    }

    //todo
//    @Override
//    public Integer queryPayStatus(String orderId)  {
//        try {
//            // 1、组装微信查询支付状态所需要的必填参数
//            Map<String,String> paramMap = new HashMap<>();
//            paramMap.put("appid",payProperties.getAppID());
//            paramMap.put("mch_id",payProperties.getMchID());
//            paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
//            paramMap.put("out_trade_no",orderId);
//            //将参数转xml
//            String paramXml = WXPayUtil.generateSignedXml(paramMap, payProperties.getKey());
//            //2、基于restTemplate工具类，调用微信支付平台，完成支付状态操作操作
//            String resultString = restTemplate.postForObject("https://api.mch.weixin.qq.com/pay/orderquery", paramXml, String.class);
//            //3、处理响应结果
//            Map<String, String> resultMap = WXPayUtil.xmlToMap(resultString);
//            //支付成功，返回状态1
//            if("SUCCESS".equals(resultMap.get("trade_state"))){
//                //更新订单状态
//                TbOrder orderStatus = new TbOrder();
//                orderStatus.setStatus(OrderStatusEnum.PAY_UP.value());
//                orderStatus.setOrderId(Long.parseLong(orderId));
//                orderStatus.setPayTime(new Date());
//                int size = this.updateById(orderStatus);
//                if(size != 1){
//                    throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
//                }
//            }
//            return "SUCCESS".equals(resultMap.get("trade_state"))?1:0;
//
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new LyException(ExceptionEnums.INVALID_PAY_STATUS);
//        }
//    }
}
